package yourobot;

import java.awt.Color;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Random;

import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;

import yourobot.bonus.Bonus;
import yourobot.bonus.BonusFactory;
import yourobot.robots.IA;
import yourobot.robots.Player;

import fr.umlv.zen.ApplicationRenderCode;

/**
 * 
 * @author mehdimasrour
 *
 */
public class Level implements ApplicationRenderCode {

	private Vec2 start;
	private Vec2 end;
	
	private static Body wallTop;
	private static Body wallBottom;
	private static Body wallLeft;
	private static Body wallRight;
	
	private final ArrayList<Wall> walls;
	private final ArrayList<Bonus> bonus;
	private final ArrayList<Player> players;
	private final ArrayList<IA> ia;
	
	
	private final static int NUMBER_WALLS = 40;
	private final static int NUMBER_BONUS = 15;
	private final static int NUMBER_IA = 5;
	public final static int AREA_RADIUS = 27;
	public final static int START_RADIUS = 54;
	
	/**
	 * 
	 * @param w : The world in which the Level is being played
	 * @param nbplayers : The number of players playing
	 */
	public Level(World w, int nbplayers){
		/*
		 * Random used to place starting and ending areas in our world
		 * but we don't want them too close and we don't want them out of the area ...
		 */
		Random r = new Random(System.nanoTime());
		start = new Vec2(r.nextFloat()*Main.MAX_X, r.nextFloat()*Main.MAX_Y);
		end = new Vec2(r.nextFloat()*Main.MAX_X, r.nextFloat()*Main.MAX_Y);
		while ((start.length()-end.length() < 400) 
				|| (start.x<START_RADIUS || start.y<START_RADIUS || start.x>Main.MAX_X-START_RADIUS || start.y>Main.MAX_Y-START_RADIUS) 
				|| (end.x<AREA_RADIUS || end.y<AREA_RADIUS || end.x>Main.MAX_X-AREA_RADIUS || end.y>Main.MAX_Y-AREA_RADIUS)){
			start = new Vec2(r.nextFloat()*Main.MAX_X, r.nextFloat()*Main.MAX_Y);
			end = new Vec2(r.nextFloat()*Main.MAX_X, r.nextFloat()*Main.MAX_Y);
		}

		walls = new ArrayList<>();
		for ( int i=0; i<NUMBER_WALLS; i++ ){
			walls.add(new Wall(w,this));
		}
		players = new ArrayList<>();
		for ( int i=1; i<(nbplayers+1); i++ ){
			players.add(new Player(i,w,getStart()));
		}
		bonus = new ArrayList<>();
		for ( int i=0; i<NUMBER_BONUS; i++){
			bonus.add(BonusFactory.newBonus());
		}
		ia = new ArrayList<>();
		for ( int i=0; i<NUMBER_IA; i++){
			ia.add(new IA(w,this));
		}
		
		/*
		 * Setting up our 4 main walls
		 */
		BodyDef bd = new BodyDef();
		bd.type = BodyType.STATIC;
		bd.position.set(0, 0);
		wallTop = w.createBody(bd);
		wallLeft = w.createBody(bd);
		bd.position.set(0, 600);
		wallBottom = w.createBody(bd);
		bd.position.set(796,0);
		wallRight = w.createBody(bd);
		PolygonShape p = new PolygonShape();
		p.setAsBox(800,1);
		FixtureDef fd = new FixtureDef();
		fd.userData = "fixedwall";
		fd.shape = p;
		fd.restitution = 0.5f;
		wallTop.createFixture(fd);
		wallBottom.createFixture(fd);
		p.setAsBox(1, 600);
		fd.shape = p;
		wallLeft.createFixture(fd);
		wallRight.createFixture(fd);
		
	}
	
	/**
	 * 
	 * @return The start area's Vec2
	 */
	public Vec2 getStart(){
		return start;
	}
	
	/**
	 * 
	 * @return The end area's Vec2
	 */
	public Vec2 getEnd(){
		return end;
	}
	
	/**
	 * 
	 * @return List of players
	 */
	public ArrayList<Player> getPlayers(){
		return  players;
	}
	
	/**
	 * 
	 * @return List of walls
	 */
	public ArrayList<Wall> getWalls(){
		return walls;
	}
	
	/**
	 * 
	 * @return true if all players are dead
	 */
	public boolean gameOver(){
		for ( Player p : players ){
			if ( !p.isDead() ) return false;
		}
		return true;
	}

	@Override
	public void render(Graphics2D graphics) {
		/*
		 * Clearing window :
		 */
		graphics.setBackground(new Color(255,255,255));
		graphics.clearRect(0, 0, 2000, 2000);
		graphics.setColor(Color.WHITE);
		graphics.fillRect(-2, -2, 810, 610);
		graphics.setColor(new Color(255, 255, 255));
		graphics.fillRect(810, 610, 400, 400);
		
		/*
		 * Drawing start and end areas :
		 */
		graphics.setColor(new Color(0, 0, 255));
		graphics.drawOval((int)start.x-START_RADIUS, (int)start.y-START_RADIUS, 2*START_RADIUS, 2*START_RADIUS);
		
		graphics.setColor(new Color(0, 255, 0));
		graphics.drawOval((int)end.x-AREA_RADIUS, (int)end.y-AREA_RADIUS, 2*AREA_RADIUS, 2*AREA_RADIUS);
		
		/*
		 * Drawing the 4 main walls :
		 */
		graphics.setColor(new Color(0, 0, 0));
		graphics.drawRect((int)wallTop.getPosition().x, (int)wallTop.getPosition().y, 800, 2);
		graphics.fillRect((int)wallTop.getPosition().x, (int)wallTop.getPosition().y, 800, 2);
		graphics.drawRect((int)wallLeft.getPosition().x, (int)wallLeft.getPosition().y, 2, 600);
		graphics.fillRect((int)wallLeft.getPosition().x, (int)wallLeft.getPosition().y, 2, 600);
		graphics.drawRect((int)wallBottom.getPosition().x, (int)wallBottom.getPosition().y, 800, 2);
		graphics.fillRect((int)wallBottom.getPosition().x, (int)wallBottom.getPosition().y, 800, 2);
		graphics.drawRect((int)wallRight.getPosition().x, (int)wallRight.getPosition().y, 2, 600);
		graphics.fillRect((int)wallRight.getPosition().x, (int)wallRight.getPosition().y, 2, 600);
		
		/*
		 * Drawing random walls :
		 */
		for ( Wall w : walls){
			w.check();
			graphics.setColor(w.getColor());
			if ( w.isH() ){
				graphics.drawRect((int)w.getPosition().x-Wall.WALL_SIZE, (int)w.getPosition().y, 2*Wall.WALL_SIZE, 2);
				graphics.fillRect((int)w.getPosition().x-Wall.WALL_SIZE, (int)w.getPosition().y, 2*Wall.WALL_SIZE,2);
			}
			else{
				graphics.drawRect((int)w.getPosition().x, (int)w.getPosition().y-Wall.WALL_SIZE, 2, 2*Wall.WALL_SIZE);
				graphics.fillRect((int)w.getPosition().x, (int)w.getPosition().y-Wall.WALL_SIZE, 2, 2*Wall.WALL_SIZE);
			}
		}
		
		/*
		 * Drawing bonuses :
		 */
		for ( Bonus b : bonus){
			graphics.setColor(b.getColor());
			graphics.drawString(String.valueOf(b.getType()), b.getPosition().x, b.getPosition().y);
		}
		
		
		/*
		 * Moving IA :
		 */
		for ( IA i : ia ){
			i.move();
			int x = (int) i.getPosition().x;
			int y = (int) i.getPosition().y;
			graphics.setColor(new Color(0, 0, 0));
			graphics.drawOval(x-IA.DEFAULT_RADIUS, y-IA.DEFAULT_RADIUS, 2*IA.DEFAULT_RADIUS, 2*IA.DEFAULT_RADIUS);
			graphics.fillOval(x-IA.DEFAULT_RADIUS, y-IA.DEFAULT_RADIUS, 2*IA.DEFAULT_RADIUS, 2*IA.DEFAULT_RADIUS);
		}
		
		/*
		 * Drawing players :
		 */
		for ( Player p : players ){
			int x = (int) p.getPosition().x;
			int y = (int) p.getPosition().y;
			p.move(bonus);
			graphics.setColor(p.getColor());
			graphics.drawOval(x-Player.DEFAULT_RADIUS, y-Player.DEFAULT_RADIUS, 2*Player.DEFAULT_RADIUS, 2*Player.DEFAULT_RADIUS);
			graphics.fillOval(x-Player.DEFAULT_RADIUS, y-Player.DEFAULT_RADIUS, 2*Player.DEFAULT_RADIUS, 2*Player.DEFAULT_RADIUS);
			/*
			 * Drawing player's stats :
			 */
			graphics.drawOval(100*p.getId(), 620, 2*Player.DEFAULT_RADIUS, 2*Player.DEFAULT_RADIUS);
			graphics.fillOval(100*p.getId(), 620, 2*Player.DEFAULT_RADIUS, 2*Player.DEFAULT_RADIUS);
			graphics.setColor(new Color(0));
			graphics.drawString(String.valueOf(p.getId()), 112*p.getId(), 650);
			graphics.drawString(String.valueOf(p.getId()), x-2, y);
			graphics.drawString(String.valueOf(Math.floor(p.getLife()))+"%", 100*p.getId(), 700);
			if ( p.getBonus() != null ){
				graphics.drawString(String.valueOf(p.getBonus().getType()), 100*p.getId(), 720);
			}
			
			/*
			 * Drawing a line for showing in which
			 * direction is going the player
			 */
			int x2 = (int)(p.getPosition().x-35*Math.cos(Math.toRadians(p.getAngle())));
			int y2 = (int)(p.getPosition().y-35*Math.sin(Math.toRadians(p.getAngle())));
			graphics.drawLine((int)p.getPosition().x, (int)p.getPosition().y, x2, y2);
			
		}
	}
}
